package com.seventh.blecore;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.inuker.bluetooth.library.BluetoothContext;
import com.inuker.bluetooth.library.Code;
import com.inuker.bluetooth.library.connect.options.BleConnectOptions;
import com.inuker.bluetooth.library.connect.response.BleConnectResponse;
import com.inuker.bluetooth.library.connect.response.BleNotifyResponse;
import com.inuker.bluetooth.library.connect.response.BleWriteResponse;
import com.inuker.bluetooth.library.model.BleGattProfile;
import com.inuker.bluetooth.library.search.SearchRequest;
import com.inuker.bluetooth.library.search.SearchResult;
import com.inuker.bluetooth.library.search.response.SearchResponse;
import com.inuker.bluetooth.library.utils.BluetoothUtils;
import com.seventh.blecore.callback.NotifyCallback;
import com.seventh.blecore.callback.ResponseCallback;
import com.seventh.blecore.callback.SearchCallback;
import com.seventh.blecore.client.BluetoothClientProxy;

import org.json.JSONArray;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static com.inuker.bluetooth.library.Code.ILLEGAL_ARGUMENT;
import static com.inuker.bluetooth.library.Code.REQUEST_SUCCESS;

/**
 * @author chengxin
 * create at 2021/4/20
 * description:具体实现类
 */
class UnityCallBleImpl implements IUnityCallBle {

    static final String EMPTY_ARRAY = "[]";
    private final BleConnectOptions mOptions = new BleConnectOptions.Builder()
            .setConnectRetry(3)   // 连接如果失败重试3次
            .setConnectTimeout(10000)   // 连接超时30s
            .setServiceDiscoverRetry(3)  // 发现服务如果失败重试3次
            .setServiceDiscoverTimeout(10000)  // 发现服务超时20s
            .build();
    @NonNull
    private final BluetoothClientProxy mClient;
    /**
     * 是否显示debug信息
     */
    private boolean mDebug = true;

    UnityCallBleImpl(@NonNull Context context) {
        this.mClient = new BluetoothClientProxy(context);
    }

    @Override
    public void setPostUi(boolean postUi) {
        mClient.setPostUi(postUi);
    }

    @Override
    public void setDebug(boolean debug) {
        this.mDebug = debug;
    }

    @Nullable
    private WeakReference<Activity> mWekActivity;

    @Override
    public void setAndroidTestActivity(@NonNull Activity activity) {
        mWekActivity = new WeakReference<>(activity);
    }

    @NonNull
    private Activity getCurrentActivity() {
        if (Utils.UNITY_PLATFORM) {
            return Utils.getUnityActivity();
        }
        Activity activity = null;
        if (mWekActivity != null) {
            activity = mWekActivity.get();
        }
        if (activity == null) {
            throw new IllegalStateException("please called setAndroidTestActivity(Activity)");
        }
        return activity;
    }

    public void showMsg(@NonNull String msg) {
        Utils.d(msg);
        if (mDebug) {
            Utils.showToast(BluetoothContext.get(), msg);
        }
    }

    @Override
    public void searchByName(@Nullable String filterName, int scanTime, boolean showDevicesDialog, @NonNull SearchCallback callback) {
        search(filterName, null, scanTime, showDevicesDialog, callback);
    }

    @Override
    public void searchByAddresses(@Nullable String filterAddresses, int scanTime, boolean showDevicesDialog, @NonNull SearchCallback callback) {
        String[] filterAddressArray = null;
        if (filterAddresses != null) {
            filterAddressArray = filterAddresses.split(",");
        }
        search(null, filterAddressArray, scanTime, showDevicesDialog, callback);
    }

    private void search(@Nullable final String filterName, @Nullable final String[] filterAddresses, int scanTime, final boolean showDevicesDialog, @NonNull final SearchCallback callback) {
        if (!mClient.isBleSupported()) {
            showMsg("设备不支持低功耗蓝牙~");
            callback.onSearchError(Code.BLE_NOT_SUPPORTED, "设备不支持蓝牙~");
            return;
        }
        if (!mClient.isBluetoothOpened()) {
            showMsg("请先打开蓝牙~");
            callback.onSearchError(Code.BLUETOOTH_DISABLED, "请先打开蓝牙~");
            return;
        }
        SearchRequest request = new SearchRequest.Builder()
                .searchBluetoothClassicDevice(scanTime, 1) // 先扫经典蓝牙5s
                .searchBluetoothLeDevice(scanTime, 1)   // 再扫BLE设备3次，每次3s
                .build();
        mClient.search(request, new SearchResponse() {
            /**
             * 所有的目标设备
             */
            private final List<SearchResult> filterResult = new ArrayList<>();

            @Override
            public void onSearchStarted() {
                showMsg("正在扫描蓝牙设备");
                callback.onSearchStarted();
            }

            @Override
            public void onDeviceFounded(SearchResult device) {
                //1.先判断是否已经包含了此设备
                if (filterResult.contains(device))
                    return;
                final String name = device.getName();
                //2.过滤设备名称
                if (filterName != null && !name.toUpperCase().contains(filterName.trim().toUpperCase()))
                    return;

                //3.过滤设备的mac地址
                if (filterAddresses != null) {
                    boolean matched = false;
                    for (String split : filterAddresses) {
                        if (split.trim().equalsIgnoreCase(device.getAddress())) {
                            matched = true;
                            //跳出当前循环
                            break;
                        }
                    }
                    if (!matched)
                        return;
                }
                filterResult.add(device);
                callback.onDeviceFounded(name, device.getAddress(), device.rssi);
            }

            @Override
            public void onSearchStopped() {
                if (filterResult.isEmpty()) {
                    showMsg("未扫描到目标设备");
                    callback.onSearchStopped(EMPTY_ARRAY, -1);
                    return;
                }
                if (showDevicesDialog) {
                    showDialog(filterResult);
                } else {
                    JSONArray jsonArray = Utils.convertToJsonArray(filterResult);
                    callback.onSearchStopped(jsonArray.toString(), -1);
                }
            }

            /**
             * 显示扫描结果
             */
            private void showDialog(final List<SearchResult> results) {
                CharSequence[] bleNames = new CharSequence[results.size()];
                for (int index = 0; index < bleNames.length; index++) {
                    bleNames[index] = results.get(index).getName();
                }
                new AlertDialog.Builder(getCurrentActivity())
                        .setTitle("请选择连接的蓝牙设备")
                        .setSingleChoiceItems(bleNames, -1, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                JSONArray jsonArray = Utils.convertToJsonArray(results);
                                callback.onSearchStopped(jsonArray.toString(), which);
                            }
                        }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        JSONArray jsonArray = Utils.convertToJsonArray(results);
                        callback.onSearchStopped(jsonArray.toString(), -1);
                    }
                }).setCancelable(false).show();
            }

            @Override
            public void onSearchCanceled() {
                showMsg("取消扫描蓝牙设备");
                callback.onSearchError(Code.REQUEST_CANCELED, "取消扫描蓝牙设备");
            }
        });
    }

    @Override
    public void connect(@NonNull final String mac, @NonNull final ResponseCallback callback) {
        mClient.connect(mac, mOptions, new BleConnectResponse() {
            @Override
            public void onResponse(int code, BleGattProfile data) {
                String msg = Utils.connectCodeToString(code);
                showMsg(msg);
                if (code == REQUEST_SUCCESS) {
                    //成功连接的情况下再绑定
                }
                callback.onResponse(mac, code, msg);
            }
        });
    }

    @Override
    public void notify(final @NonNull String mac, @NonNull String service, @NonNull String character, @NonNull final NotifyCallback callback) {
        if (!BluetoothUtils.isDeviceConnected(mac)) {
            //状态错误咯
            callback.onResponse(mac, ILLEGAL_ARGUMENT, "设备未连接，请先连接蓝牙设备");
            return;
        }
        mClient.notify(mac, UUID.fromString(service), UUID.fromString(character), new BleNotifyResponse() {
            @Override
            public void onNotify(UUID service, UUID character, byte[] value) {
                callback.onByteArray(mac, new ByteArray(value));
            }

            @Override
            public void onResponse(int code) {
                showMsg(code == REQUEST_SUCCESS ? "notify成功~" : "notify失败~");
                callback.onResponse(mac, code, code == REQUEST_SUCCESS ? "notify成功~" : "notify失败~");
            }
        });
    }

    @Override
    public void write(boolean noResponse, @NonNull final String mac, @NonNull String service, @NonNull String character,
                      @NonNull byte[] data, @NonNull final ResponseCallback callback) {
        if (!BluetoothUtils.isDeviceConnected(mac)) {
            //状态错误咯
            callback.onResponse(mac, ILLEGAL_ARGUMENT, "设备未连接，请先连接蓝牙设备");
            return;
        }
        UUID serviceUUID = UUID.fromString(service);
        UUID characterUUID = UUID.fromString(character);
        BleWriteResponse bleWriteResponse = new BleWriteResponse() {
            @Override
            public void onResponse(int code) {
                showMsg(code == REQUEST_SUCCESS ? "发送成功" : "发送失败");
                callback.onResponse(mac, code, code == REQUEST_SUCCESS ? "发送成功" : "发送失败");
            }
        };
        if (noResponse) {
            mClient.writeNoRsp(mac, serviceUUID, characterUUID, data, bleWriteResponse);
        } else {
            mClient.write(mac, serviceUUID, characterUUID, data, bleWriteResponse);
        }
    }

    @Override
    public int getBondState(@NonNull String mac) {
        return mClient.getBondState(mac);
    }

    @Override
    public int getConnectStatus(@NonNull String mac) {
        return mClient.getConnectStatus(mac);
    }

    @Override
    public boolean isDeviceConnected(@NonNull String mac) {
        return BluetoothUtils.isDeviceConnected(mac);
    }

    @Override
    public void disconnect(@NonNull String mac) {
        mClient.disconnect(mac);
    }

    @Override
    public void stopSearch() {
        mClient.stopSearch();
    }
}
